package dormouse.vfs.ui.renderers;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;

import javax.swing.JComponent;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.commons.vfs2.FileFilter;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.VFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;

import dormouse.Dormouse;
import dormouse.gui.StripedTable;
import dormouse.vfs.FileUtil;
import dormouse.vfs.event.ILocationChangeEvent;
import dormouse.vfs.ui.FileListTableModel;
import dormouse.vfs.ui.FileTableCellRenderer;
import dormouse.vfs.ui.actions.ActionFactory;

/**
 * This bean is used to display the contents of a file list in a tabular format.
 * 
 */
public class FileListTableBean extends AbstractFileListRenderer {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4421290646576042602L;
	/** Class logger. */
	private static final Logger log = LoggerFactory.getLogger(FileListTableBean.class);
	private JScrollPane scroller = new JScrollPane();
	private StripedTable table = new StripedTable();

	/**
	 * Constructor. Uses the user's home directory.
	 */
	public FileListTableBean() {
		super("View As List");
		init(new FileListTableModel());
	}



	/**
	 * Constructor. Uses an arbitrary directory.
	 * 
	 * @param dir
	 *            Directory to be displayed.
	 */
	public FileListTableBean(FileObject dir) {
		super("View As List");
		init(new FileListTableModel(dir));
	}

	/**
	 * Constructor. This constructor creates a FileListTableBean from a file
	 * list model.
	 * 
	 * @param model
	 */
	public FileListTableBean(FileListTableModel model) {
		super("View As List");
		init(model);
	}

	public void setModel(FileListTableModel theModel) {
		this.table.setModel(theModel);
	}

	private void init(FileListTableModel model) {
		this.setLayout(new BorderLayout());
		this.add(this.scroller, BorderLayout.CENTER);

		this.table.setPreferredScrollableViewportSize(new Dimension(400, 300));
		this.table.setAutoCreateColumnsFromModel(true);
		this.table.setAutoCreateRowSorter(true);
		

		this.table.setModel(model);
		this.table.getColumnModel().getColumn(0).setCellRenderer(new FileTableCellRenderer());

		this.table
				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

		this.table.getSelectionModel().addListSelectionListener(
				new ListSelectionListener() {

					public void valueChanged(ListSelectionEvent evt) {
						int row = FileListTableBean.this.table.getSelectedRow();
						FileListTableModel model = (FileListTableModel) FileListTableBean.this.table
								.getModel();
						FileObject file = (FileObject) model.getFileAt(row);

						// notify the listeners that a file has been selected.
						FileListTableBean.this
								.notifyFileSelectionListeners(file);

					}
				});

		this.table.addMouseListener(new MouseAdapter() {

			public void mouseClicked(MouseEvent e) {
				JTable src = (JTable) e.getSource();
				FileListTableModel model = (FileListTableModel) src.getModel();

				int rowIndex = src.getSelectedRow();
				if (rowIndex >= 0) {
					FileObject file = model.getFileAt(rowIndex);

					try {
						FileType fileType = file.getType();
						if (fileType == FileType.FILE && e.isPopupTrigger()) {
							JPopupMenu menu = ActionFactory.getMenu(file);
							menu.setVisible(true);
						} else if (fileType == FileType.FOLDER) {
							FileListTableBean.this
									.notifyFileSelectionListeners(file);
							Dormouse.getApplication().setDirectory(file);
						}
					} catch (FileSystemException ex) {
						log.error(ex.getMessage(), ex);
					}
				}

			}
		});
		this.scroller.getViewport().add(this.table);
	}

	/**
	 * This method gets the file list model used by the table.
	 * 
	 * @return
	 */
	public FileListTableModel getFileListModel() {
		return (FileListTableModel) this.table.getModel();
	}

	/**
	 * This method applies a FileFilter to the underlying FileListTableModel.
	 * 
	 * @param selectedFilter
	 *            The file filter to be applied.
	 */
	public void applyFilter(FileFilter selectedFilter) {
		FileListTableModel model = (FileListTableModel) this.table.getModel();
		List<FileObject> filteredList = model.getFilteredList(selectedFilter);
		this.init(new FileListTableModel(filteredList));
	}

	
	@Override
	public void render(FileObject dir, Predicate<FileObject> pred) {
		
		try {
			List<FileObject> fileList = FileUtil.filterFileList(dir.getChildren(), pred);		
			this.init(new FileListTableModel(fileList));
		} catch (FileSystemException e) {
			log.debug(e.getMessage(), e);
		}
		
		
	}

	
	public void render(String dir) {
		try {
			render(VFS.getManager().resolveFile(dir), null);
		} catch (FileSystemException e) {
			e.printStackTrace();
		}

	}

	public JComponent getComponent() {
		return this;
	}



	@Override
	public void render(String dir, Predicate<FileObject> predicate) {
		try {
			FileObject file = VFS.getManager().resolveFile(dir);
			render(file, predicate);			
		} catch (FileSystemException e) {
			log.debug(e.getMessage(), e);
		}
		
	}



	@Override
	public void render(List<FileObject> fileList,
			Predicate<FileObject> predicate) {
		
		List<FileObject> filteredList = FileUtil.filterFileList(fileList, predicate);		
		this.init(new FileListTableModel(filteredList));
	}



	@Override
	public void notifyFileSelectionListeners(FileObject selectedFile) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public void locationChanged(ILocationChangeEvent event) {
		FileObject file = event.getCurrentLocation();
		render(file, null);
	}
}
